bufferevent
1. 基本概念
- bufferevent:在套接字之上封装了输入/输出缓冲与回调机制的 I/O 对象,避免手写
read/write和边沿触发细节。 - 事件循环:
event_base驱动,所有 I/O、超时、信号都在此 loop 内调度。
2. 关键 API
buferevent_socket_new()
1 | struct bufferevent* bufferevent_socket_new( |
说明
fd = -1:由 libevent 负责创建 socket,更简洁。BEV_OPT_CLOSE_ON_FREE:在bufferevent_free()时自动关闭 socket。BEV_OPT_DEFER_CALLBACKS:把回调延迟到事件循环安全点执行,减少重入问题。
buferevent_socket_connect()
1 | int bufferevent_socket_connect( |
说明
- 非阻塞发起连接;成功返回 0,失败返回 -1(同时触发 event 回调中的
BEV_EVENT_ERROR)。 - 连接成功后会触发 event 回调中的
BEV_EVENT_CONNECTED。
如果要用主机名而非 IP,推荐
bufferevent_socket_connect_hostname()(需配合evdns_base进行异步解析)。
3. 最小可用示例(IPv4)
1 |
|
4. 使用要点与常见坑
回调必须先设再 connect
先bufferevent_setcb()+bufferevent_enable(),再调用bufferevent_socket_connect(),避免早到事件丢失。超时设置
bufferevent_set_timeouts()同时设置读/写超时。- 连接阶段通常依赖写超时触发(因为 connect 过程中会等待可写)。
水位(可选)
- 读水位:
bufferevent_setwatermark(bev, EV_READ, low, high)
当输入缓冲超过high时会暂时禁用读事件,防止内存暴涨。 - 写水位:同理控制输出缓冲积压。
- 读水位:
线程安全
- libevent 可多线程,但一个
event_base通常只在一个线程内跑;跨线程提交任务请用event_base_once()或管道/通知机制。
- libevent 可多线程,但一个
DNS 支持(推荐)
- 异步解析:
evdns_base_new(base, 1)+bufferevent_socket_connect_hostname(bev, dns, AF_UNSPEC, "example.com", 80) - 避免阻塞式
getaddrinfo()。
- 异步解析:
清理顺序
- 一般在
event_cb收到EOF/ERROR/TIMEOUT后bufferevent_free();loop 退出后event_base_free()。
- 一般在
错误定位
BEV_EVENT_ERROR时使用EVUTIL_SOCKET_ERROR()+evutil_socket_error_to_string()打印 errno。- 常见:
ECONNREFUSED(服务未起)、ETIMEDOUT(网络/防火墙/超时)、EHOSTUNREACH。
选项建议
BEV_OPT_CLOSE_ON_FREE:免漏句柄BEV_OPT_DEFER_CALLBACKS:减少重入与回调嵌套- 如需逐线程回调可考虑
BEV_OPT_THREADSAFE(需要启用evthread_use_pthreads()等)。
5. 主机名连接(带 DNS)的示例(简版)
1 |
|
6. 小结(流程速记)
event_base_new()bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS)bufferevent_setcb()→bufferevent_enable(EV_READ|EV_WRITE)→bufferevent_set_timeouts()bufferevent_socket_connect()(或_connect_hostname())- 在
event_cb处理BEV_EVENT_CONNECTED / EOF / ERROR / TIMEOUT - 退出时
bufferevent_free()、event_base_free()
7. 进阶建议
- TLS:用
bufferevent_openssl_socket_new()包装 SSL 会话,接口与普通bev基本一致。 - 背压控制:配合水位、分块写入,避免写缓冲过大。
- 协议层:在
read_cb内从evbuffer取数据,做半包/粘包处理(如定长头 + 可变体)。